package com.zshy.base.core.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.zshy.base.core.contract.exception.BeanConversionException;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.*;
import org.springframework.util.CollectionUtils;

import javax.management.ReflectionException;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.util.*;

/**
 * bean对象的转换工具类
 *
 * @author zhouhengzhe
 */
@Slf4j
@UtilityClass
public class BeanKit {
    private final String REFLECT_ERROR = "反射获取转换对象异常";
    private final String COMMA = ",";

    /**
     * 将Map类型的属性映射到指定的Java对象中。
     *
     * @param map    待映射的Map类型的属性
     * @param object 待映射的目标Java对象
     * @throws BeanConversionException 如果目标对象实例化失败或属性拷贝失败，则抛出此异常
     */
    public void mapToObject(Map map, Object object) {
        // 判断map和object是否为null
        if (map == null || object == null) {
            // 如果为null，则抛出BeanConversionException异常
            throw new BeanConversionException("map and object cannot be null");
        }
        // 创建一个BeanWrapper对象，用于操作目标Java对象的属性
        BeanWrapper beanWrapper = new BeanWrapperImpl(object);
        // 创建一个PropertyValues对象，用于保存Map类型的属性
        PropertyValues propertyValues = new MutablePropertyValues(map);
        // 将Map类型的属性设置到目标Java对象中
        beanWrapper.setPropertyValues(propertyValues, true, true);
    }

    /**
     * 将列名转换为字段名
     *
     * @param columnName 列名
     * @return 转换后的字段名，如果转换失败则返回null
     */
    public String changeColumnToFieldName(String columnName) {
        if (columnName == null) {
            // 防止空指针异常
            return null;
        }
        // 将列名按"_"分割为数组
        String[] array = columnName.split("_");
        // 创建StringBuilder对象，用于拼接字段名
        StringBuilder sb = new StringBuilder(columnName.length());
        for (String s : array) {
            if (!sb.isEmpty()) {
                // 首字母大写
                sb.append(Character.toUpperCase(s.charAt(0)));
            } else {
                // 首个单词首字母小写
                sb.append(Character.toLowerCase(s.charAt(0)));
            }
            if (s.length() > 1) {
                // 其余部分小写
                sb.append(s.substring(1).toLowerCase());
            }
        }
        // 返回转换后的字符串
        return sb.toString();
    }

    /**
     * 将对象转换为Map类型
     *
     * @param obj 要转换的对象
     * @return 转换后的Map对象，包含对象的属性和属性值
     */
    public Map<String, Object> toMap(Object obj) {
        // 调用另一个重载的toMap方法，传入obj、true和null作为参数
        return toMap(obj, true, null);
    }

    /**
     * 将对象转换为Map类型（去除null值）
     *
     * @param obj 要转换的对象
     * @return 转换后的Map对象，包含对象的属性与属性值，但去除null值
     */
    public Map<String, Object> toMapClean(Object obj) {
        // 调用toMap方法，并传递obj、false和null作为参数
        // 第二个参数false表示去除null值，第三个参数null在此处未使用
        return toMap(obj, false, null);
    }

    /**
     * 将对象转换成Map
     *
     * @param obj          要转换的对象
     * @param withNull     是否包含null值
     * @param ignoreFields 要忽略的字段
     * @return 转换后的Map对象
     */
    public Map<String, Object> toMap(Object obj, boolean withNull, String... ignoreFields) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        // 判断对象是否为String类型
        // 移除对String的特殊处理
        if (obj instanceof String s) {
            map.put(s, obj);
        } else {
            // 调用另一个toMap方法，传入obj、map、withNull和ignoreFields
            toMap(obj, map, withNull, ignoreFields);
        }
        return map;
    }

    /**
     * 将map列表转换为对象列表
     *
     * @param mapList    存放Map对象的列表
     * @param objectList 存放转换后对象的列表
     * @param clazz      目标对象的Class对象
     */
    public void mapsToObjects(List<Map<String, Object>> mapList, List objectList, Class clazz) {
        if (CollUtil.isNotEmpty(mapList) && objectList != null && clazz != null) {
            // 遍历map列表
            for (Map<String, Object> map : mapList) {
                // 通过反射获取目标对象的实例
                Object object = gainInstanceByReflect(clazz);
                // 将Map对象的键值对映射到目标对象的属性中
                mapToObject(map, object);
                // 将转换后的对象添加到对象列表中
                objectList.add(object);
            }
        }
    }

    /**
     * 将源对象列表复制到目标对象列表中，目标对象类型由目标类Class对象确定
     *
     * @param sourceList  源对象列表，不能为空，否则不执行复制操作
     * @param targetList  目标对象列表，用于存放复制后的目标对象，不能为空
     * @param targetClass 目标对象的Class对象，用于创建目标对象实例
     * @throws BeanConversionException 如果目标对象实例化失败或属性拷贝失败，则抛出此异常
     */
    public void copyObjectListToNewInstances(List sourceList, List targetList, Class targetClass) {
        // 检查源对象列表是否为空，目标对象列表是否非空
        if (CollUtil.isNotEmpty(sourceList) && targetList != null) {
            // 遍历源对象列表
            for (Object source : sourceList) {
                // 通过反射获取目标对象的实例
                Object target = gainInstanceByReflect(targetClass);
                // 将源对象的属性值复制到目标对象中
                BeanUtils.copyProperties(source, target);
                // 将目标对象添加到目标对象列表中
                targetList.add(target);
            }
        }
    }

    /**
     * 将字符串列表转换为逗号分隔的字符串。
     *
     * @param list 要转换的字符串列表
     * @return 转换后的逗号分隔的字符串
     */
    public String listToString(List<String> list) {
        if (list == null) {
            // 或者可以抛出异常，具体取决于业务需求
            return "";
        }
        // 调用重载的listToString方法，传入字符串列表和逗号分隔符
        return listToString(list, COMMA);
    }

    /**
     * 将字符串列表转换为由指定分隔符连接起来的字符串
     *
     * @param list      字符串列表
     * @param separator 分隔符
     * @return 转换后的字符串
     */
    public String listToString(List<String> list, String separator) {
        if (list == null || separator == null) {
            throw new BeanConversionException("List or separator cannot be null");
        }
        // 调用重载的listToString方法，将字符串列表、分隔符和null作为参数传入
        return listToString(list, separator, null);
    }

    /**
     * 将字符串列表转换成由指定分隔符和包围符连接的字符串。
     *
     * @param list      字符串列表，不能为空
     * @param separator 分隔符，如果为null，则不使用分隔符
     * @param surround  包围符，如果为null，则不使用包围符
     * @return 转换后的字符串
     */
    public String listToString(List<String> list, String separator, String surround) {
        if (list == null) {
            throw new BeanConversionException("List cannot be null.");
        }
        StringBuilder builder = new StringBuilder();
        // 检查列表是否为空
        if (CollUtil.isNotEmpty(list)) {
            int i = 0;

            // 遍历列表中的每个字符串
            for (String str : list) {
                // 如果不是第一个字符串，则添加分隔符
                if (i++ > 0) {
                    builder.append(separator);
                }
                // 判断是否使用包围符
                if (surround != null) {
                    // 使用包围符将字符串包围起来并添加到结果中
                    builder.append(surround).append(str).append(surround);
                } else {
                    // 不使用包围符，直接将字符串添加到结果中
                    builder.append(str);
                }
            }
        }
        // 将StringBuilder对象转换为字符串并返回
        return builder.toString();
    }

    /**
     * 通过反射获取指定Class对象的实例
     *
     * @param clazz 要获取实例的Class对象
     * @return 返回一个Object对象，表示clazz的实例
     * @throws ReflectionException 如果无法通过反射获取clazz的实例，则抛出此异常
     */
    public Object gainInstanceByReflect(Class clazz) {
        // 获取clazz的完整类名
        String className = clazz.getName();
        // 调用另一个重载的gainInstanceByReflect方法，传入完整类名获取实例
        return gainInstanceByReflect(className);
    }

    /**
     * 通过反射获取指定类名的实例对象
     *
     * @param className 类名
     * @return 实例对象
     * @throws BeanConversionException 如果反射过程中出现异常，则封装为自定义的BeanConversionException异常并抛出
     */
    private Object gainInstanceByReflect(String className) {
        try {
            Class<?> clazz = Class.forName(className);
            // 获取无参构造器
            Constructor<?> constructor = clazz.getDeclaredConstructor();
            // 设置可访问，以便访问私有构造器
            constructor.setAccessible(true);
            // 创建实例
            return constructor.newInstance();
        } catch (ReflectiveOperationException e) {
            // 捕获与反射相关的所有异常
            log.error(REFLECT_ERROR, e);
            throw new BeanConversionException(e);
        }
    }

    /**
     * 将源对象转换为目标对象
     *
     * @param source 源对象
     * @param target 目标对象
     */
    public void objectToObject(Object source, Object target) {
        // 调用重载的objectToObject方法以进行具体的转换操作，
        // 传入源对象、目标对象以及三个默认值：
        // - false 是否忽略空值
        // - true 是否包含创建信息
        // - true 是否包含更新信息
        objectToObject(source, target, false, true, true);
    }

    /**
     * 将源对象转换为目标对象
     *
     * @param source     源对象
     * @param target     目标对象
     * @param ignoreNull 是否忽略null值，true表示忽略，false表示不忽略
     */
    public void objectToObject(Object source, Object target, boolean ignoreNull) {
        // 调用重载的objectToObject方法，并传入源对象、目标对象、
        // - ignoreNull 是否忽略空值
        // - false 是否包含创建信息
        // - false 是否包含更新信息
        objectToObject(source, target, ignoreNull, false, false);
    }

    /**
     * 将源对象属性值拷贝到目标对象。
     *
     * @param source         源对象
     * @param target         目标对象
     * @param ignoreNull     是否忽略空值
     * @param withCreateInfo 是否包含创建信息
     * @param withUpdateInfo 是否包含更新信息
     */
    public void objectToObject(Object source, Object target, boolean ignoreNull, boolean withCreateInfo, boolean withUpdateInfo) {
        if (source != null && target != null) {
            // 创建一个列表用于存储需要忽略的属性名
            List<String> ignorePropertiesList = Lists.newArrayList();
            // 如果不需要包含创建信息
            if (!withCreateInfo) {
                // 添加创建者属性名到忽略列表
                ignorePropertiesList.add("creator");
                // 添加创建者编码属性名到忽略列表
                ignorePropertiesList.add("createBy");
                // 添加创建时间属性名到忽略列表
                ignorePropertiesList.add("createTime");
            }
            // 如果不需要包含更新信息
            if (!withUpdateInfo) {
                // 添加更新者属性名到忽略列表
                ignorePropertiesList.add("updater");
                // 添加更新者编码属性名到忽略列表
                ignorePropertiesList.add("updateBy");
                // 添加更新时间属性名到忽略列表
                ignorePropertiesList.add("updateTime");
            }
            // 如果需要忽略空值
            if (ignoreNull) {
                // 调用ignoreNull方法，忽略源对象中的空值属性
                ignoreNull(source, ignorePropertiesList);
            }
            // 使用BeanUtils工具类将源对象的属性值拷贝到目标对象中，同时忽略指定的属性
            BeanUtils.copyProperties(source, target, ignorePropertiesList.toArray(new String[0]));
        }
    }

    /**
     * 忽略源对象中的空值属性，将空值属性名添加到忽略属性列表中
     *
     * @param source               源对象
     * @param ignorePropertiesList 忽略属性列表
     */
    private void ignoreNull(Object source, List<String> ignorePropertiesList) {
        if (source == null || ignorePropertiesList == null) {
            throw new BeanConversionException("源对象或忽略属性列表不能为null");
        }
        // 获取源对象的所有字段
        Field[] fields = source.getClass().getDeclaredFields();
        try {
            // 遍历字段数组
            for (Field field : fields) {
                // 设置字段可访问
                field.setAccessible(true);
                // 判断字段的值是否为空
                if (field.get(source) == null) {
                    // 如果为空，则将字段名添加到忽略属性列表中
                    ignorePropertiesList.add(field.getName());
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException var7) {
            // 捕获异常并记录日志
            log.error(REFLECT_ERROR, var7);
            throw new BeanConversionException(var7);
        }
    }

    /**
     * 将源对象属性值拷贝到目标对象。
     *
     * @param source     源对象
     * @param target     目标对象
     * @param ignoreNull 是否忽略空值
     * @param isUpdate   是否为更新操作
     */
    public void objectToObject(Object source, Object target, boolean ignoreNull, boolean isUpdate) {
        // 调用重载的objectToObject方法，传入源对象、目标对象、是否忽略空值、是否为更新操作的相反值以及固定参数true
        objectToObject(source, target, ignoreNull, !isUpdate, true);
    }

    /**
     * 将Map转换为JavaBean对象
     *
     * @param map 要转换的Map对象
     * @param obj 目标JavaBean对象
     */
    public void transMap2Bean(Map<String, Object> map, Object obj) {
        // 检查输入参数是否为null
        if (map == null || obj == null) {
            throw new BeanConversionException("Map or Object cannot be null");
        }
        try {
            // 获取目标JavaBean的BeanInfo
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            // 获取JavaBean的属性描述符数组
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            // 遍历属性描述符数组
            for (PropertyDescriptor property : propertyDescriptors) {
                // 获取属性的名称
                String key = property.getName();

                // 如果Map中包含该属性名称的键
                if (map.containsKey(key)) {
                    // 获取属性值
                    Object value = map.get(key);

                    // 获取属性的setter方法
                    Method setter = property.getWriteMethod();
                    // 调用setter方法设置属性值到JavaBean对象中
                    setter.invoke(obj, value);
                }
            }
        } catch (Exception e) {
            // 记录异常日志，提供更详细的异常信息和堆栈跟踪
            log.error("Map --> Bean Error", e);
            throw new BeanConversionException(e);
        }
    }

    /**
     * 将源对象属性值拷贝到目标对象，并返回目标对象。
     *
     * @param sourceObject           源对象
     * @param targetClass 目标对象的Class类型
     * @param <T>         目标对象的类型
     * @param <Q>         源对象的类型
     * @return 目标对象
     */
    public <T, Q> T of(Q sourceObject, Class<T> targetClass) {
        // 如果源对象为null，则返回null
        if (Objects.isNull(sourceObject)) {
            return null;
        }
        // 创建目标对象实例
        T targetObject = BeanUtils.instantiate(targetClass);
        // 调用objectToObject方法，将源对象属性值拷贝到目标对象
        objectToObject(sourceObject, targetObject, true, true, true);
        // 返回目标对象
        return targetObject;
    }

    /**
     * 将Map对象转换为指定类型的JavaBean对象
     *
     * @param map         待转换的Map对象，键为属性名，值为属性值
     * @param targetClass 目标JavaBean对象的Class类型
     * @param <T>         目标JavaBean对象的类型
     * @return 转换后的目标JavaBean对象，如果转换失败返回null
     */
    public <T> T ofMap(Map<String, Object> map, Class<T> targetClass) {
        // 判断Map对象是否为空且不为空集合
        if (!Objects.isNull(map) && !map.isEmpty()) {
            try {
                // 使用BeanUtils工具类实例化目标JavaBean对象
                T t = BeanUtils.instantiate(targetClass);
                // 调用mapToObject方法将Map对象的属性值拷贝到目标JavaBean对象中
                mapToObject(map, t);
                // 返回转换后的目标JavaBean对象
                return t;
            } catch (Exception e) {
                // 这里可以记录日志或进行其他异常处理
                throw new BeanConversionException(e);
            }
        }
        // 如果Map对象为空或为空集合，则返回null
        return null;
    }

    /**
     * 将源对象列表属性值拷贝到目标对象列表中，并返回目标对象列表。
     *
     * @param sources     源对象列表
     * @param targetClass 目标对象的Class类型
     * @param <T>         目标对象的类型
     * @param <Q>         源对象的类型
     * @return 转换后的目标对象列表，如果源对象列表为空，则返回空列表
     */
    public <T, Q> List<T> ofList(List<Q> sources, Class<T> targetClass) {
        // 如果源对象列表为空
        if (CollUtil.isEmpty(sources)) {
            // 返回空列表
            return new ArrayList<T>();
        }
        // 创建一个新的目标对象列表
        List<T> targetList = new ArrayList<>();
        // 调用方法将源对象列表的属性值拷贝到目标对象列表中
        copyObjectListToNewInstances(sources, targetList, targetClass);
        // 返回目标对象列表
        return targetList;

    }

    /**
     * 将Map列表转换为指定类型的JavaBean列表
     *
     * @param sources     待转换的Map列表，每个Map对象的键为属性名，值为属性值
     * @param targetClass 目标JavaBean对象的Class类型
     * @param <T>         目标JavaBean对象的类型
     * @return 转换后的目标JavaBean列表，如果转换失败或源列表为空则返回空列表
     */
    public <T> List<T> ofMapList(List<Map<String, Object>> sources, Class<T> targetClass) {
        // 如果源列表为空，则返回空列表
        if (CollUtil.isEmpty(sources)) {
            return new ArrayList<>();
        }
        // 创建一个目标JavaBean列表
        List<T> targetList = new ArrayList<>();
        try {
            // 调用mapsToObjects方法将Map列表转换为JavaBean列表，并存储到目标列表中
            mapsToObjects(sources, targetList, targetClass);
        } catch (Exception e) {
            // 这里可以记录日志或进行其他异常处理
            throw new BeanConversionException(e);
        }
        // 返回目标JavaBean列表
        return targetList;

    }

    /**
     * 获取给定对象source中所有值为null的属性名称数组。
     *
     * @param source 给定对象，不能为null。
     * @return 返回一个字符串数组，包含所有值为null的属性名称。
     * 如果source中没有值为null的属性，则返回一个长度为0的数组。
     * @throws BeanConversionException 如果source为null。
     */
    public String[] getNullPropertyNames(Object source) {
        if (source == null) {
            throw new BeanConversionException("Source object cannot be null.");
        }
        // 创建一个BeanWrapper对象，传入给定对象source
        BeanWrapper src = new BeanWrapperImpl(source);
        // 获取给定对象的所有属性描述符
        PropertyDescriptor[] pds = src.getPropertyDescriptors();
        // 创建一个HashSet集合，用于存储值为null的属性名称
        Set<String> emptyNames = Sets.newHashSet();

        // 遍历属性描述符数组
        for (PropertyDescriptor pd : pds) {
            // 获取指定属性的值
            Object srcValue = src.getPropertyValue(pd.getName());
            // 判断属性值是否为null
            if (srcValue == null) {
                // 将属性名称添加到集合中
                emptyNames.add(pd.getName());
            }
        }

        // 创建一个字符串数组，长度为集合的大小
        String[] result = new String[emptyNames.size()];
        // 将集合转换为字符串数组并返回
        return emptyNames.toArray(result);
    }

    /**
     * 将源对象source的属性值复制到目标对象target中。
     *
     * @param source 源对象，不能为空。
     * @param target 目标对象，不能为空。
     * @throws BeanConversionException 如果source或target为空。
     */
    public void copy(Object source, Object target) {
        // 检查源对象和目标对象是否都不为空
        if (source == null) {
            throw new IllegalArgumentException("Source object cannot be null.");
        }
        if (target == null) {
            throw new IllegalArgumentException("Target object cannot be null.");
        }

        // 判断源对象和目标对象是否都是集合类型
        if (source instanceof Collection<?> && target instanceof Collection<?>) {
            Collection<?> sourceCollection = (Collection<?>) source;
            Collection<?> targetCollection = (Collection<?>) target;
            // 确保目标集合大小足够，或者可以动态扩展（如ArrayList），否则可能引发异常

            Iterator<?> itSource = sourceCollection.iterator();
            // 假设目标集合可以动态扩展或者已经具有足够的大小来存储源集合的元素
            // 如果不是，则需要额外的逻辑来处理目标集合的大小问题
            for (Object targetElement : targetCollection) {
                if (!itSource.hasNext()) {
                    break; // 防止源集合元素少于目标集合时抛出NoSuchElementException
                }
                Object sourceElement = itSource.next();
                // 假设BeanKit.copy能正确处理null值，或者确保sourceElement不为null
                BeanKit.copy(sourceElement, targetElement);
            }
            return;
        }
        // 拷贝对象属性
        String[] nullPropertyNames = getNullPropertyNames(source);
        BeanUtils.copyProperties(source, target, nullPropertyNames);
    }

    /**
     * 复制对象。
     *
     * @param source 源对象，不能为空。
     * @param target 目标对象的类型，不能为空。
     * @param <T>    目标对象的类型。
     * @return 返回目标对象的副本。
     * @throws BeanConversionException 如果source或target为null。
     */
    public <T> T copy(Object source, Class<T> target) {
        // 检查source和target是否为null
        if (source == null) {
            throw new BeanConversionException("Source object cannot be null.");
        }
        if (target == null) {
            throw new BeanConversionException("Target class cannot be null.");
        }
        // 调用重载的copy方法，无需进行不安全的类型转换
        return copy(source, target, (Class) null);
    }

    /**
     * 将源对象source的属性值复制到目标对象target中，返回目标对象的副本。
     *
     * @param source      源对象，不能为空
     * @param target      目标对象的类型
     * @param targetSuper 目标对象的父类类型，可以为null
     * @param <T>         目标对象的类型
     * @return 返回目标对象的副本
     * @throws BeanConversionException 如果source为null
     */
    public <T> T copy(Object source, Class<T> target, Class<?> targetSuper) {
        if (source == null) {
            throw new BeanConversionException("Source object cannot be null.");
        }
        if (target == null) {
            throw new BeanConversionException("Target class cannot be null.");
        }

        Object targetObject = null;
        try {
            // 创建目标对象的实例
            targetObject = target.newInstance();
            // 使用BeanUtils工具类将源对象的属性值复制到目标对象中
            BeanUtils.copyProperties(source, targetObject, targetSuper);
        } catch (Exception e) {
            // 如果在复制过程中出现异常，则记录错误日志
            log.error("Convert error: source={}, target={}, targetSuper={}", source, target, targetSuper, e);
            throw new BeanConversionException(e);
        }
        return (T) targetObject;
    }

    /**
     * 复制集合对象。
     *
     * @param sourceList 集合对象，不能为空
     * @param target     目标对象的类型
     * @param <T>        目标对象的类型
     * @return 返回目标对象列表
     * @throws BeanConversionException 如果sourceList为null
     */
    public <T> List<T> copy(Collection<?> sourceList, Class<T> target) {
        if (CollectionUtils.isEmpty(sourceList)) {
            // 如果源集合为空，则返回空列表
            return Collections.emptyList();
        }
        if (target == null) {
            // 如果目标对象类型为null，则抛出空指针异常
            throw new NullPointerException("Target class cannot be null");
        }
        // 创建目标集合对象，初始容量与源集合大小相同
        ArrayList<T> targetList = new ArrayList<>(sourceList.size());
        try {
            for (Object source : sourceList) {
                // 创建目标对象的实例
                T targetObject = target.newInstance();
                // 使用BeanUtils工具类将源对象的属性值复制到目标对象中
                BeanUtils.copyProperties(source, targetObject);
                // 将目标对象添加到目标集合中
                targetList.add(targetObject);
            }
            return targetList;
        } catch (Exception e) {
            // 如果在复制过程中出现异常，则记录错误日志
            log.error("convert error {} {} {}", new Object[]{sourceList, target, e});
            throw new BeanConversionException(e);
        }
    }

    /**
     * 将源对象的属性值复制到目标对象中，并返回目标对象的副本。
     *
     * @param source           源对象，不能为空
     * @param target           目标对象的类型
     * @param ignoreProperties 要忽略的属性名数组，可传多个参数
     * @param <T>              目标对象的类型
     * @return 返回目标对象的副本
     * @throws BeanConversionException 如果source为null
     */
    public <T> T copy(Object source, Class<T> target, String... ignoreProperties) {
        if (source == null) {
            // 如果源对象为空，则返回null
            return null;
        }
        Object targetObject = null;
        try {
            // 创建目标对象实例，使用推荐的构造器方式
            Constructor<?> constructor = target.getDeclaredConstructor();
            constructor.setAccessible(true);
            targetObject = constructor.newInstance();
            // 使用BeanUtils工具类将源对象的属性值复制到目标对象中，并忽略指定的属性
            BeanUtils.copyProperties(source, targetObject, ignoreProperties);
        } catch (Exception e) {
            // 如果在复制过程中出现异常，则记录错误日志
            log.error("convert error: source={}, target={}", source, target, e);
            throw new BeanConversionException(e);
        }
        // 返回目标对象的副本
        return (T) targetObject;

    }

    /**
     * 复制集合对象。
     *
     * @param sourceList       源集合对象，不能为空
     * @param target           目标对象的类型
     * @param ignoreProperties 要忽略的属性名数组，可传多个参数
     * @param <T>              目标对象的类型
     * @return 返回目标对象列表
     * @throws BeanConversionException 如果sourceList为null
     */
    public <T> List<T> copy(Collection<?> sourceList, Class<T> target, String... ignoreProperties) {
        if (sourceList == null) {
            // 如果源集合为null，则返回空列表
            return Collections.emptyList();
        }
        if (target == null) {
            // 如果目标对象类型为null，则抛出空指针异常
            throw new NullPointerException("Target class cannot be null");
        }
        // 创建一个目标集合，初始容量与源集合大小相同
        ArrayList<T> targetList = new ArrayList<>(sourceList.size());
        try {
            // 遍历源集合中的每个元素
            for (Object source : sourceList) {
                // 创建目标对象的实例
                T targetObject = target.newInstance();
                // 使用BeanUtils工具类将源对象的属性值复制到目标对象中，并忽略指定的属性
                BeanUtils.copyProperties(source, targetObject, ignoreProperties);
                // 将目标对象添加到目标集合中
                targetList.add(targetObject);
            }
        } catch (Exception e) {
            // 如果在复制过程中出现异常，则记录错误日志并抛出异常
            log.error("Convert error: sourceList={}, target={}", sourceList, target, e);
            throw new BeanConversionException(e);
        }
        // 返回目标集合
        return targetList;
    }

    /**
     * 将源对象属性转换为Map类型，并填充到目标Map中
     *
     * @param source          源对象，不能为null
     * @param target          目标Map，不能为null
     * @param withNull        是否将源对象中的null值也填充到目标Map中
     * @param ignoredFieldCol 需要忽略的字段列表，可传多个参数
     * @throws BeanConversionException 当发生反射错误时，抛出ServiceException异常
     */
    public void toMap(Object source, Map target, boolean withNull, String... ignoredFieldCol) {
        Assert.notNull(source, "source is required");
        Assert.notNull(target, "target is required");
        Set<String> ignores = new HashSet<>();
        if (ignoredFieldCol != null) {
            ignores.addAll(Arrays.asList(ignoredFieldCol));
        }
        try {
            /**
             * 使用Java的内省机制来获取一个对象的属性描述符（PropertyDescriptor）
             *
             * 使用Java的内省机制（Introspector）来获取一个对象的属性描述符（PropertyDescriptor）。通过调用getPropertyDescriptors()方法，
             * 它将返回一个包含所有可读写属性的数组。然后，通过遍历这个数组，我们可以获取每个属性的写方法（setter方法）。
             *
             * 在这段代码中，source是要检查的对象，它的类必须符合JavaBean的规范，即具有公共的getter和setter方法
             * 。getWriteMethod()方法将返回与该属性关联的写方法（如果有的话）。
             * 注意，Query的子类不要加@Accessors(chain = true)注解，否则会导致Introspector.getBeanInfo()方法获取不到属性,从而导致条件获取失败
             */
            PropertyDescriptor[] pds = Introspector.getBeanInfo(source.getClass()).getPropertyDescriptors();
            // 遍历属性描述符数组
            for (PropertyDescriptor pd : pds) {
                // 获取属性的写方法（setter方法）
                Method method = pd.getWriteMethod();
                if (method != null) {
                    // 获取属性的名称
                    String fieldName = pd.getName();
                    // 如果该属性不在忽略列表中
                    if (!ignores.contains(fieldName)) {
                        // 获取属性的读方法（getter方法）
                        Method getter = pd.getReadMethod();
                        if (getter != null) {
                            // 调用读方法获取属性值，并将其放入目标Map中
                            target.put(fieldName, getter.invoke(source));
                        } else if (withNull) {
                            // 如果需要填充null值，则将null放入目标Map中
                            target.put(fieldName, null);
                        }
                    }
                }
            }
        } catch (InvocationTargetException | IllegalAccessException | IntrospectionException e) {
            throw new BeanConversionException(400, String.format("%s %s", REFLECT_ERROR, e.getLocalizedMessage()));
        }
    }
    /**
     * 判断给定对象是否为空。
     *
     * @param obj 要判断的对象
     * @return 如果对象为空，则返回true；否则返回false
     */
    private boolean isEmpty(Object obj) {
        // 如果对象为空，则返回true
        if (obj == null) {
            return true;
            // 如果对象不是Optional类型
        } else if (!(obj instanceof Optional o)) {
            // 如果对象是CharSequence类型
            if (obj instanceof CharSequence c) {
                // 返回字符串是否为空
                return c.isEmpty();
                // 如果对象是数组类型
            } else if (obj.getClass().isArray()) {
                // 返回数组长度是否为0
                return Array.getLength(obj) == 0;
                // 如果对象是集合类型
            } else if (obj instanceof Collection coll) {
                // 返回集合是否为空
                return coll.isEmpty();
                // 如果对象是Map类型
            } else {
                // 返回Map是否为空
                return obj instanceof Map m && m.isEmpty();
            }
            // 如果对象是Optional类型
        } else {
            // 返回Optional对象是否为空
            return o.isEmpty();
        }
    }
}
